{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "5bd02725-6d98-4c2f-8a3a-e5ac7da3bedb",
   "metadata": {},
   "source": [
    "# A brief introduction to the OpenAI API\n",
    "\n",
    "Before starting to create the chatbot, I think it is interesting to explain a couple of points:\n",
    "\n",
    "- The roles within a conversation with OpenAI.\n",
    "- How is the conversations’ memory preserved?\n",
    "\n",
    "If you prefer to start creating the chatbot, just move to the section: Creating the Chatbot with OpenAI and GPT.\n",
    "\n",
    "## The roles in OpenAI messages\n",
    "\n",
    "One of the lesser-known features of language models such as GPT 3.5 is that the conversation occurs between several roles. We can identify the user and the assistant, but there is a third role called system, which allows us to better configure how the model should behave.\n",
    "\n",
    "When we use tools like ChatGPT, we always assume the role of the user, but the API lets us choose which Role we want to send to the model, for each sentence.\n",
    "\n",
    "To send text containing our part of the dialog to the model, we must use the `ChatCompletion.create` function, indicating, at least, the model to use and a list of messages.\n",
    "\n",
    "Each message in the list contains a role and the text we want to send to the model.\n",
    "\n",
    "Here is an example of the list of messages that can be sent using the three available roles.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "72d71c22-42d9-42aa-b8bb-7fc55e2246c7",
   "metadata": {},
   "outputs": [],
   "source": [
    " messages=[\n",
    "        {\"role\": \"system\", \"content\": \"You are an OrderBot in a fastfood restaurant.\"},\n",
    "        {\"role\": \"user\", \"content\": \"I have only 10 dollars, what can I order?\"},\n",
    "        {\"role\": \"assistant\", \"content\": \"We have the fast menu for 7 dollars.\"},\n",
    "        {\"role\": \"user\", \"content\": \"Perfect! Give me one! \"}\n",
    "    ]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55a18d2a-039d-42fe-aac0-d309f4f4849d",
   "metadata": {},
   "source": [
    "Let’s take a closer look at the three existing roles:\n",
    "\n",
    "- **System:** We can tell the model how we want it to behave and tell it how its personality and type of response should be. Somehow, it allows us to configure the basic operation of the model. OpenAI says that this role will become more important in the next models, even though now its importance is relatively small in GPT 3.5.\n",
    "- **User:** These are the phrases that come from the user.\n",
    "- **Assistant:** These are the responses returned by the model. With the API, we can send responses that say they came from the model, even if they came from somewhere else.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46178bd6-fa47-4a70-bdb4-668ee6ebfac3",
   "metadata": {},
   "source": [
    "# Vertical Chat\n",
    "A sample how to build a chat for small businees using:\n",
    "\n",
    "* GPT 35\n",
    "* Panel\n",
    "* OpenAI\n",
    "\n",
    "\n",
    "This is just a simple sample to start to understand how the OpenAI API works, and how to create Prompts. It Is really far from beign a complete solution.\n",
    "We are going to introduce some interesting points:\n",
    "\n",
    "* The roles in a conversation.\n",
    "* How is the conversations’ memory preserved?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92c71f2f-b937-473b-b355-b290f5d5558d",
   "metadata": {},
   "source": [
    "In this notebook, we'll explore small prompt engineering techniques and recommendations that will help us elicit responses from the models that are better suited to our needs.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10928b67-82c9-4032-9217-290e3f8a96bb",
   "metadata": {},
   "source": [
    "# Creating the Chatbot with OpenAI and GPT\n",
    "\n",
    "The first thing we have to consider is that we are going to need an OpenAI payment account to use their service and that we will have to report a valid credit card. But let’s not worry, I’ve been using it a lot for development and testing, and I can assure you that the cost is negligible.\n",
    "\n",
    "Doing all the tests for this article, I think they cost me €0.07. We could only be surprised if we upload something to production that becomes a HIT. Even so, we can establish the monthly consumption limit that we want.\n",
    "\n",
    "The first thing, as always, is to know if we have the necessary libraries installed. In case we work on Google Colab, I think we only have to install two, OpenAI and panel.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7b619062-96a7-48f0-a4ad-7da84308f70a",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install openai==1.1.1\n",
    "!pip install panel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "39e3e313-1dd7-4527-8fb3-06714bda65de",
   "metadata": {},
   "outputs": [],
   "source": [
    "import openai\n",
    "\n",
    "openai.api_key=\"your-api-key\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1035a4d-44f2-4ced-a88a-7f673aed9826",
   "metadata": {},
   "source": [
    "## Formatting the answer with Few Shot Samples.\n",
    "To obtain the model's response in a specific format, we have various options, but one of the most convenient is to use Few-Shot Samples. This involves presenting the model with pairs of user queries and example responses.\n",
    "\n",
    "Large models like GPT-3.5 respond well to the examples provided, adapting their response to the specified format.\n",
    "\n",
    "Depending on the number of examples given, this technique can be referred to as:\n",
    "\n",
    "Zero-Shot.\n",
    "One-Shot.\n",
    "Few-Shots.\n",
    "With One Shot should be enough, and it is recommended to use a maximum of six shots. It's important to remember that this information is passed in each query and occupies space in the input prompt.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92717756-3e20-401e-b497-065056a86a30",
   "metadata": {},
   "source": [
    "My key is stored in a file where I keep the keys. But if you like, you can inform it directly in the notebook, or save the key in a file, with a .py extension.\n",
    "\n",
    "In any case, make sure that nobody can ever know the value of the Key; otherwise, they could make calls to the OpenAI API that you would end up paying for.\n",
    "\n",
    "Now we are going to define two functions, which will be the ones that will contain the logic of maintaining the memory of the conversation.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "925a746e-e8de-4a44-a9bd-bfe7b4d73951",
   "metadata": {},
   "outputs": [],
   "source": [
    "def continue_conversation(messages, temperature=0):\n",
    "    response = openai.chat.completions.create(\n",
    "        model=\"gpt-3.5-turbo\",\n",
    "        messages=messages,\n",
    "        temperature=temperature,\n",
    "    )\n",
    "    #print(str(response.choices[0].message[\"content\"]))\n",
    "    return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b398809-62a2-441e-bed5-9d8f1c2310b4",
   "metadata": {},
   "source": [
    "This function is very simple, it just makes a call to the OpenAI API that allows you to have a conversation.\n",
    "\n",
    "Inside the function, we are calling OpenAI with the following parameters:\n",
    "\n",
    "- `model`: the model we want to use.\n",
    "- `messages`: the messages part of the conversation.\n",
    "- `temperature`: It is a numerical value between 0 and 1, which indicates how imaginative the model can be when generating the response. The smaller the value, the less original the model’s response will be.\n",
    "\n",
    "As you know, a language generation model does not always give the same answers to the same inputs. The lower the value of temperature, the more similar the result will be for the same inputs, even repeating itself in many cases.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c7a441b-103a-44d5-bce6-56271f9afb28",
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_prompts_conversation(_):\n",
    "    #Get the value introduced by the user\n",
    "    prompt = client_prompt.value_input\n",
    "    client_prompt.value = ''\n",
    "\n",
    "    #Append to the context the User prompt.\n",
    "    context.append({'role':'user', 'content':f\"{prompt}\"})\n",
    "\n",
    "    #Get the response.\n",
    "    response = continue_conversation(context)\n",
    "\n",
    "    #Add the response to the context.\n",
    "    context.append({'role':'assistant', 'content':f\"{response}\"})\n",
    "\n",
    "    #Update the panels to show the conversation.\n",
    "    panels.append(\n",
    "        pn.Row('User:', pn.pane.Markdown(prompt, width=600)))\n",
    "    panels.append(\n",
    "        pn.Row('Assistant:', pn.pane.Markdown(response, width=600)))\n",
    "\n",
    "    return pn.Column(*panels)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99829f22-c099-4f93-9972-934dcf0328a3",
   "metadata": {},
   "source": [
    "This function is responsible for collecting user input, incorporating it into the context or conversation, calling the model, and incorporating its response into the conversation. That is, it is responsible for managing the memory! It is as simple as adding phrases with the correct format to a list, where each sentence is formed by the role and the phrase.\n",
    "\n",
    "Now is the time for the prompt!\n",
    "\n",
    "This is an LLM model. We are not going to program, we are going to try to make it behave as we want by giving it some instructions. At the same time, we must also provide it with enough information so that it can do its job properly informed.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2dd9063d-80cf-41c0-b357-39610f015aad",
   "metadata": {},
   "outputs": [],
   "source": [
    "context = [ {'role':'system', 'content':\"\"\"\n",
    "Act as an OrderBot, you work collecting orders in a delivery only fast food restaurant called\n",
    "My Dear Frankfurt. \\\n",
    "First welcome the customer, in a very friendly way, then collects the order. \\\n",
    "You wait to collect the entire order, beverages included \\\n",
    "then summarize it and check for a final \\\n",
    "time if everything is ok or the customer wants to add anything else. \\\n",
    "Finally you collect the payment.\\\n",
    "Make sure to clarify all options, extras and sizes to uniquely \\\n",
    "identify the item from the menu.\\\n",
    "You respond in a short, very friendly style. \\\n",
    "The menu includes \\\n",
    "burger  12.95, 10.00, 7.00 \\\n",
    "frankfurt   10.95, 9.25, 6.50 \\\n",
    "sandwich   11.95, 9.75, 6.75 \\\n",
    "fries 4.50, 3.50 \\\n",
    "salad 7.25 \\\n",
    "Toppings: \\\n",
    "extra cheese 2.00, \\\n",
    "mushrooms 1.50 \\\n",
    "martra sausage 3.00 \\\n",
    "canadian bacon 3.50 \\\n",
    "romesco sauce 1.50 \\\n",
    "peppers 1.00 \\\n",
    "Drinks: \\\n",
    "coke 3.00, 2.00, 1.00 \\\n",
    "sprite 3.00, 2.00, 1.00 \\\n",
    "vichy catalan 5.00 \\\n",
    "\"\"\"} ]\n",
    "\n",
    "#Creating the panel.\n",
    "pn.extension()\n",
    "\n",
    "panels = []\n",
    "\n",
    "client_prompt = pn.widgets.TextInput(value=\"Hi\", placeholder='Enter text here…')\n",
    "button_conversation = pn.widgets.Button(name=\"talk\")\n",
    "\n",
    "interactive_conversation = pn.bind(add_prompts_conversation, button_conversation)\n",
    "\n",
    "dashboard = pn.Column(\n",
    "    client_prompt,\n",
    "    pn.Row(button_conversation),\n",
    "    pn.panel(interactive_conversation, loading_indicator=True),\n",
    ")\n",
    "\n",
    "dashboard"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "749aaf1a-5b20-488d-a64d-459253b834d6",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
